package umage.core;

import java.io.File;
import java.io.FileFilter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Modifier;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class PackageLoader<T> {
	
	public static class ExtensionFilter implements FileFilter {
		private String ext;
		
		public ExtensionFilter(String ext) {
			this.ext = ext;
		}
		
		public String getExtension() {
			return ext;
		}
		
		@Override
		public boolean accept(File file) {
			return file.toString().endsWith(ext);
		}
	}
	
	public String getClassBinaryName(String packName, String className) {
		StringBuilder builder = new StringBuilder();
		builder.append(packName);
		builder.append('.');
		builder.append(className.replace(".class", ""));
		return builder.toString();
	}
	
	public boolean checkClassModifiers(Class<?> c) {
		int modifiers = c.getModifiers();
		if (Modifier.isAbstract(modifiers)) return false;
		if (Modifier.isInterface(modifiers)) return false;
		return true;
	}
	
	public List<Class<T>> loadPackage(String packageName, Class<T> filter) {
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		
		Collection<String> classNames = ResourceList.getPackageResources(packageName, ".class");
		
		// Convert the class filenames to classes
		List<Class<T>> classes = new ArrayList<>(classNames.size());
		
		// Verify the classes are instantiatable and add them to the output list
		for (String classFile : classNames) {
			try {
				Class<?> currentClass = cl.loadClass(getClassBinaryName(packageName, classFile));
				
				@SuppressWarnings("unchecked")
				Class<T> verifiedClass = (Class<T>)currentClass.asSubclass(filter);
				
				if (checkClassModifiers(verifiedClass)) classes.add(verifiedClass);
			} catch (ClassCastException ex) {
				// Do nothing, just don't add bad classes to the list
			} catch (ClassNotFoundException e) {
				// Do nothing, just don't add bad classes to the list
			}
		}
		
		return classes;
	}

}